#include <fstream>
#include <cstdlib>
#include <iostream>
#include "configloader.h"
#define NOT_FOUND std::string::npos

ConfigLoader::ConfigLoader(const char* name){
    std::ifstream file(name);

    if(file.is_open()){
        unsigned char table = 1;
        std::string line, tmp_line = "";
        while(getline(file, line)){
            line = deleteAllChars(line, "\n");
            line = deleteAllChars(line, "\t");
            size_t f;
            if((f = line.find_first_of("#")) != NOT_FOUND)
                line.replace(f, line.size()-f, "");

            if(line.empty())
                continue;

            if(line.find_first_of("{") != NOT_FOUND && line.find_first_of("{") < line.find_first_of("\"")){
                std::string tmp = line.substr(line.find_first_of("{"), line.size());
                if(tmp.find_first_of("{") == 0 && tmp.find_first_of("}") == tmp.size()-1)
                    table = 1;
                else
                    table = 2;
            }
            else if(line.find_first_of("}") != NOT_FOUND && table == 2)
                table = 3;

            if(table == 2)
                tmp_line += line;
            else if(table == 3){
                tmp_line += line;
                line = tmp_line;
                table = 1;
                tmp_line.clear();
            }

            if(table == 1){
                stack.push_back(line);
                std::cout<<line<<std::endl;
            }
        }

        if(table == 2)
            throw std::string("Table variable syntax error. Missing \"}\".");
    }else
        throw std::string("File not found!");

    file.close();
}

ConfigLoader::~ConfigLoader(){
    vars.clear();
    t_vars.clear();
};

Table ConfigLoader::PraseTable(std::string str){
    size_t f1, f2;
    if((f1  = str.find_first_of("{")) != NOT_FOUND)
        str.replace(f1, 1, "");

    if((f1  = str.find_first_of("}")) != NOT_FOUND)
        str.replace(f1, 1, "");

    Table tbl;

    if(str[str.size()-1] != ',')
        str += ",";

    int i = 0;
    while((f1  = str.find_first_of(",")) != NOT_FOUND){
        std::string buf = str.substr(0, f1);
        str = str.substr(f1+1, str.size());
        buf = deleteAllChars(buf, ",");

        Var v;
        f1 = buf.find_first_of("\"");
        f2 = buf.find_last_of("\"");
        if(f1 == f2 && f1 != NOT_FOUND && f2 != NOT_FOUND)
            throw std::string("String variable syntax error. Missing \".");
        else if(f1 != NOT_FOUND && f2 != NOT_FOUND){
            v.str = deleteAllChars(buf.substr(f1, f2), "\"");
            v.type = VAR_STRING;
            buf = deleteAllChars(buf, " ");
            f1 = buf.find_first_of("=");
            if(f1 != NOT_FOUND)
                tbl[buf.substr(0, f1)] = v;
            else{
                tbl[to_string<int>(i)] = v;
                i++;
            }
            continue;
        }

        buf = deleteAllChars(buf, " ");

        f1 = buf.find_first_of("=");
        if(buf.find("true") != NOT_FOUND){
            v._bool = true;
            v.type = VAR_BOOL;
            if(f1 != NOT_FOUND)
                tbl[buf.substr(0, f1)] = v;
            else{
                tbl[to_string<int>(i)] = v;
                i++;
            }
            continue;
        }
        else if(buf.find("false") != NOT_FOUND){
            v._bool = false;
            v.type = VAR_BOOL;
            if(f1 != NOT_FOUND)
                tbl[buf.substr(0, f1)] = v;
            else{
                tbl[to_string<int>(i)] = v;
                i++;
            }
            continue;
        }

        f2 = buf.find_first_of(".");
        if(f2 == NOT_FOUND){
            v._int = atoi(buf.substr(f1+1, buf.size()).c_str());
            v.type = VAR_INT;
            if(f1 != NOT_FOUND)
                tbl[buf.substr(0, f1)] = v;
            else{
                v._int = atoi(buf.substr(f1+1, buf.size()).c_str());
                tbl[to_string<int>(i)] = v;
                i++;
            }
        }
        else if(f2 != NOT_FOUND){
            v._float = atof(buf.substr(f1+1, buf.size()).c_str());
            v.type = VAR_FLOAT;
            if(f1 != NOT_FOUND)
                tbl[buf.substr(0, f1)] = v;
            else{
                tbl[to_string<int>(i)] = v;
                i++;
            }
        }
    }

    return tbl;
}

void ConfigLoader::Prase(){
    //Table tmp_stack;
    for(Stack::iterator it = stack.begin(); it != stack.end(); it++){
        std::string buf = *it;
        size_t f1, f2;
        Var v;

        f1 = buf.find_first_of("{");
        f2 = buf.find_last_of("}");
        if(f1 != NOT_FOUND && f2 != NOT_FOUND){
            f2 = buf.find_first_of("=");
            Table tbl = PraseTable(buf.substr(f1, buf.size()));
            t_vars[deleteAllChars(buf.substr(0, f2), " ")] = tbl;
            continue;
        }

        f1 = buf.find_first_of("\"");
        f2 = buf.find_last_of("\"");
        if(f1 == f2 && f1 != NOT_FOUND && f2 != NOT_FOUND)
            throw std::string("String variable syntax error. Missing \".");
        else if(f1 != NOT_FOUND && f2 != NOT_FOUND){
            v.str = deleteAllChars(buf.substr(f1, f2), "\"");
            v.type = VAR_STRING;
            buf = deleteAllChars(buf, " ");
            f1 = buf.find_first_of("=");
            vars[buf.substr(0, f1)] = v;
            continue;
        }

        buf = deleteAllChars(buf, " ");

        f1 = buf.find_first_of("=");
        if(buf.find("true") != NOT_FOUND){
            v._bool = true;
            v.type = VAR_BOOL;
            vars[buf.substr(0, f1)] = v;
            continue;
        }
        else if(buf.find("false") != NOT_FOUND){
            v._bool = false;
            v.type = VAR_BOOL;
            vars[buf.substr(0, f1)] = v;
            continue;
        }

        f2 = buf.find_first_of(".");
        if(f1 != NOT_FOUND && f2 == NOT_FOUND){
            v._int = atoi(buf.substr(f1+1, buf.size()).c_str());
            v.type = VAR_INT;
            vars[buf.substr(0, f1)] = v;
        }
        else if(f1 != NOT_FOUND && f2 != NOT_FOUND){
            v._float = atof(buf.substr(f1+1, buf.size()).c_str());
            v.type = VAR_FLOAT;
            vars[buf.substr(0, f1)] = v;
        }
    }
}

std::string ConfigLoader::deleteAllChars(std::string str, const char* c){
    while(true){
        size_t f;

        if((f  = str.find_first_of(c)) == NOT_FOUND)
            break;

        str.replace(f, 1, "");
    }

    return str;
}
